/*
 * FreeModbus Libary: STM32 Port
 * Copyright (C) 2013 Armink <armink.ztl@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * File: $Id: portserial_m.c,v 1.60 2013/08/13 15:07:05 Armink add Master Functions $
 */

#include "port.h"

/* ----------------------- Modbus includes ----------------------------------*/
#include "board.h"
#include "mb.h"
#include "mbport.h"
#include "sys_conf.h"

#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
/* ----------------------- static functions ---------------------------------*/
static void prvvUARTTxReadyISR(UCHAR ucMB_Number);
static void prvvUARTRxISR(UCHAR ucMB_Number);
/* ----------------------- Start implementation -----------------------------*/

void vMBMasterPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable, UCHAR ucMB_Number)
{
    switch (ucMB_Number) {
        case MB_MASTER_0:
            if (xRxEnable) {
                /* 485通信时，等待串口移位寄存器中的数据发送完成后，再去使能485的接收、失能485的发送*/
                while (!USART_GetFlagStatus(MB_MASTER_00, USART_FLAG_TC))
                    ;
                MASTER_RS485_RECEIVE_MODE;
                USART_ITConfig(MB_MASTER_00, USART_IT_RXNE, ENABLE);
            } else {
                MASTER_RS485_SEND_MODE;
                USART_ITConfig(MB_MASTER_00, USART_IT_RXNE, DISABLE);
            }
            if (xTxEnable) {
                USART_ITConfig(MB_MASTER_00, USART_IT_TXE, ENABLE);
            } else {
                USART_ITConfig(MB_MASTER_00, USART_IT_TXE, DISABLE);
            }
            break;
        case MB_MASTER_1:
            if (xRxEnable) {
                /* 485通信时，等待串口移位寄存器中的数据发送完成后，再去使能485的接收、失能485的发送*/
                while (!USART_GetFlagStatus(UART4, USART_FLAG_TC))
                    ;
                MASTER_RS485_RECEIVE_MODE_01;
                USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);
            } else {
                MASTER_RS485_SEND_MODE_01;
                USART_ITConfig(UART4, USART_IT_RXNE, DISABLE);
            }
            if (xTxEnable) {
                USART_ITConfig(UART4, USART_IT_TXE, ENABLE);  //?
            } else {
                USART_ITConfig(UART4, USART_IT_TXE, DISABLE);
            }
            break;
        default:
            break;
    }
}

void vMBMasterPortClose(UCHAR ucMB_Number)
{
    switch (ucMB_Number) {
        case MB_MASTER_0:
            USART_ITConfig(MB_MASTER_00, USART_IT_TXE | USART_IT_RXNE, DISABLE);
            USART_Cmd(MB_MASTER_00, DISABLE);
            break;
        case MB_MASTER_1:
            USART_ITConfig(UART4, USART_IT_TXE | USART_IT_RXNE, DISABLE);
            USART_Cmd(UART4, DISABLE);
            break;
        default:
            break;
    }
}
//默认一个主机 串口3 波特率可设置  奇偶检验可设置
BOOL xMBMasterPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity, UCHAR ucMB_Number)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef  NVIC_InitStructure;

    switch (ucMB_Number) {
        case MB_MASTER_0:
            //======================时钟初始化=======================================
            RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO, ENABLE);
            RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
            GPIO_PinRemapConfig(GPIO_FullRemap_USART3, ENABLE);
            //======================IO初始化=======================================
            // USART1_TX
            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
            GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
            GPIO_InitStructure.GPIO_Pin   = UART3_GPIO_TX;
            GPIO_Init(UART3_GPIO, &GPIO_InitStructure);
            // USART1_RX
            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
            GPIO_InitStructure.GPIO_Pin  = UART3_GPIO_RX;
            GPIO_Init(UART3_GPIO, &GPIO_InitStructure);
            //配置485发送和接收模式
            //    TODO   暂时先写A0 等之后组网测试时再修改
            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
            GPIO_InitStructure.GPIO_Pin  = UART3_DIR_GPIO_PIN;
            GPIO_Init(UART3_DIR_GPIO, &GPIO_InitStructure);
            //======================串口初始化=======================================
            USART_InitStructure.USART_BaudRate = ulBaudRate;
            //设置校验模式
            switch (eParity) {
                case MB_PAR_NONE:  //无校验
                    USART_InitStructure.USART_Parity     = USART_Parity_No;
                    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
                    break;
                case MB_PAR_ODD:  //奇校验
                    USART_InitStructure.USART_Parity     = USART_Parity_Odd;
                    USART_InitStructure.USART_WordLength = USART_WordLength_9b;
                    break;
                case MB_PAR_EVEN:  //偶校验
                    USART_InitStructure.USART_Parity     = USART_Parity_Even;
                    USART_InitStructure.USART_WordLength = USART_WordLength_9b;
                    break;
                default:
                    return FALSE;
            }

            USART_InitStructure.USART_StopBits            = USART_StopBits_1;
            USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
            USART_InitStructure.USART_Mode                = USART_Mode_Rx | USART_Mode_Tx;
            //			if (ucPORT != UPORT_MBMASTER)
            //				return FALSE;

            ENTER_CRITICAL_SECTION();  //关全局中断

            USART_Init(MB_MASTER_00, &USART_InitStructure);
            USART_ITConfig(MB_MASTER_00, USART_IT_RXNE, ENABLE);
            USART_Cmd(MB_MASTER_00, ENABLE);

            //=====================中断初始化======================================
            //设置NVIC优先级分组为Group2：0-3抢占式优先级，0-3的响应式优先级
            //	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
            NVIC_InitStructure.NVIC_IRQChannel                   = USART3_IRQn;
            NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
            NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 1;
            NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
            NVIC_Init(&NVIC_InitStructure);
            EXIT_CRITICAL_SECTION();  //开全局中断
            break;
        case MB_MASTER_1:
            //======================时钟初始化=======================================
            RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
            RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);

            //======================IO初始化=========================================
            // UART4_TX
            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
            GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
            GPIO_InitStructure.GPIO_Pin   = UART4_GPIO_TX;
            GPIO_Init(UART4_GPIO, &GPIO_InitStructure);
            // UART4_RX
            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
            GPIO_InitStructure.GPIO_Pin  = UART4_GPIO_RX;
            GPIO_Init(UART4_GPIO, &GPIO_InitStructure);
            //配置485发送和接收模式
            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
            GPIO_InitStructure.GPIO_Pin  = UART4_DIR_GPIO_PIN;
            GPIO_Init(UART4_DIR_GPIO, &GPIO_InitStructure);
            //======================串口初始化=======================================
            USART_InitStructure.USART_BaudRate = ulBaudRate;
            //设置校验模式
            switch (eParity) {
                case MB_PAR_NONE:  //无校验
                    USART_InitStructure.USART_Parity     = USART_Parity_No;
                    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
                    break;
                case MB_PAR_ODD:  //奇校验
                    USART_InitStructure.USART_Parity     = USART_Parity_Odd;
                    USART_InitStructure.USART_WordLength = USART_WordLength_9b;
                    break;
                case MB_PAR_EVEN:  //偶校验
                    USART_InitStructure.USART_Parity     = USART_Parity_Even;
                    USART_InitStructure.USART_WordLength = USART_WordLength_9b;
                    break;
                default:
                    return FALSE;
            }

            USART_InitStructure.USART_StopBits            = USART_StopBits_1;
            USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
            USART_InitStructure.USART_Mode                = USART_Mode_Rx | USART_Mode_Tx;
            //			if (ucPORT != UPORT_MBMASTER_01)
            //				return FALSE;

            ENTER_CRITICAL_SECTION();  //关全局中断

            USART_Init(UART4, &USART_InitStructure);
            USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);
            USART_Cmd(UART4, ENABLE);

            //=====================中断初始化======================================
            //设置NVIC优先级分组为Group2：0-3抢占式优先级，0-3的响应式优先级
            //	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
            NVIC_InitStructure.NVIC_IRQChannel                   = UART4_IRQn;
            NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
            NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;
            NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
            NVIC_Init(&NVIC_InitStructure);

            EXIT_CRITICAL_SECTION();  //开全局中断

            break;
        default:
            break;
    }

    return TRUE;
}

BOOL xMBMasterPortSerialPutByte(CHAR ucByte, UCHAR ucMB_Number)
{
    switch (ucMB_Number) {
        case MB_MASTER_0:
            USART_SendData(MB_MASTER_00, ucByte);
            break;
        case MB_MASTER_1:
            USART_SendData(UART4, ucByte);
            break;
        default:
            break;
    }
    return TRUE;
}

BOOL xMBMasterPortSerialGetByte(CHAR *pucByte, UCHAR ucMB_Number)
{
    switch (ucMB_Number) {
        case MB_MASTER_0:
            *pucByte = USART_ReceiveData(MB_MASTER_00);
            break;
        case MB_MASTER_1:
            *pucByte = USART_ReceiveData(UART4);
            break;
        default:
            break;
    }
    return TRUE;
}

/*
 * Create an interrupt handler for the transmit buffer empty interrupt
 * (or an equivalent) for your target processor. This function should then
 * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
 * a new character can be sent. The protocol stack will then call
 * xMBPortSerialPutByte( ) to send the character.
 */
static void prvvUARTTxReadyISR(UCHAR ucMB_Number)
{
    pxMBMasterFrameCBTransmitterEmpty(ucMB_Number);
}

/*
 * Create an interrupt handler for the receive interrupt for your target
 * processor. This function should then call pxMBFrameCBByteReceived( ). The
 * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
 * character.
 */
static void prvvUARTRxISR(UCHAR ucMB_Number)
{
    pxMBMasterFrameCBByteReceived(ucMB_Number);
}
/*******************************************************************************
 * Function Name  : USART3_IRQHandler
 * Description    : This function handles USART1 global interrupt request.
 * Input          : None
 * Output         : None
 * Return         : None
 *******************************************************************************/
void USART3_IRQHandler(void)
{
    rt_interrupt_enter();
    //溢出错误
    if (USART_GetFlagStatus(MB_MASTER_00, USART_FLAG_ORE) == SET) {
        prvvUARTRxISR(MB_MASTER_0);
    }
    //接收中断
    if (USART_GetITStatus(MB_MASTER_00, USART_IT_RXNE) == SET) {
        USART_ClearITPendingBit(MB_MASTER_00, USART_IT_RXNE);
        prvvUARTRxISR(MB_MASTER_0);
    }
    //发送中断
    if (USART_GetITStatus(MB_MASTER_00, USART_IT_TXE) == SET) {
        prvvUARTTxReadyISR(MB_MASTER_0);
    }
    rt_interrupt_leave();
}
void UART4_IRQHandler(void)
{
    rt_interrupt_enter();
    //溢出错误
    if (USART_GetFlagStatus(UART4, USART_FLAG_ORE) == SET) {
        prvvUARTRxISR(MB_MASTER_1);
    }
    //接收中断
    if (USART_GetITStatus(UART4, USART_IT_RXNE) == SET) {
        USART_ClearITPendingBit(UART4, USART_IT_RXNE);
        prvvUARTRxISR(MB_MASTER_1);
    }
    //发送中断
    if (USART_GetITStatus(UART4, USART_IT_TXE) == SET) {
        prvvUARTTxReadyISR(MB_MASTER_1);
    }
    rt_interrupt_leave();
}

#endif
